# -*- coding: utf-8 -*-
"""
@Time ： 2025/4/9 9:32
@Auth ： 桉柠
@File ：loginPage.py
@Motto:主体页
"""
import json
import logging
import os
import subprocess
import sys
import time

import requests
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal, QSettings, QUrl, QTranslator, QLibraryInfo, QDateTime, QDate, \
    QPropertyAnimation
from PyQt5.QtGui import QDesktopServices, QColor
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QInputDialog, QMessageBox, QDialog, QTableWidgetItem, \
    QAbstractItemView, QAction, QHeaderView, QTableWidget, QPushButton, QFileDialog
from openpyxl.workbook import Workbook

import utils
from DBManager import DBManager
from DownloadThread import DownloadThread
from WorkerThread import WorkerThread
from addAndUpdate import AddStoreDialog, EditStoreDialog, AddProductDialog, EditProductDialog, ComboBoxDelegate
from aotoget import Ui_MainWindow
from app_config import AppConfig
from dialogWindows import TimerDialog
from logger_util import Logger
from login import Ui_Form
import warnings
from qt_material import apply_stylesheet

warnings.filterwarnings("ignore", category=DeprecationWarning)

class LoginThread(QThread):
    login_result = pyqtSignal(dict)  # 自定义信号，用于传递登录结果

    def __init__(self, appcode):
        super().__init__()
        self.appname = 'AutoGET'
        self.appcode = appcode
        self.session = requests.Session()

    def run(self):
        # 登录逻辑放在这里
        try:
            response = requests.post(AppConfig.Business.SITE_URL, data={
                'appname': self.appname,
                'appcode': self.appcode
            })
            json_data = response.content.decode('utf-8-sig')
            data = json.loads(json_data)
        except Exception as e:
            data = {'status': '404', 'msg': str(e)}

        self.login_result.emit(data)  # 发送登录结果信号


class Window(QWidget, Ui_Form):
    def __init__(self):
        super().__init__()
        self.appcode = None
        self.image_index = 2  # 图片切换
        self.setupUi(self)
        self.initUI()

    def initUI(self):

        self.setWindowFlag(Qt.FramelessWindowHint)  # 去掉默认的窗口边框
        self.setAttribute(Qt.WA_TranslucentBackground)  # 设置背景为透明
        self.setStyleSheet("background: transparent;")  # 设置样式表使背景透明
        # 定时器，用于每隔 2 秒切换图片
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.switch_image)
        self.timer.start(2000)  # 2 秒间隔
        # 绑定鼠标悬停事件
        self.leftFrame.installEventFilter(self)

    def eventFilter(self, obj, event):
        """事件过滤器，处理鼠标悬浮事件"""
        if obj == self.leftFrame:
            if event.type() == event.Enter:
                self.timer.stop()  # 停止定时器
                self.imgFrame.setStyleSheet("background-image: url(:/icon/qrcode.png);")
            elif event.type() == event.Leave:
                self.timer.start()  # 重新启动定时器
                self.switch_image()  # 切换图片以确保显示正确的图片
        return super().eventFilter(obj, event)

    def switch_image(self):
        """切换图片的方法"""
        if self.image_index == 1:
            self.image_index = 2
            self.imgFrame.setStyleSheet("background-image: url(:/ico/1.png);")
        else:
            self.image_index = 1
            self.imgFrame.setStyleSheet("background-image: url(:/ico/qrcode.png);")

    def login(self):
        self.msgFrameShow('299', '正在验证,请稍后...')
        self.lognBtn.setEnabled(True)
        self.appcode = self.passWord.text()

        # 创建登录线程
        self.login_thread = LoginThread(self.appcode)
        self.login_thread.login_result.connect(self.handle_login_result)  # 连接信号
        self.login_thread.start()  # 启动线程

    def handle_login_result(self, data):
        self.lognBtn.setEnabled(True)  # 登录结束，重新启用按钮
        self.msgFrameShow(data['status'], data['msg'])  # 显示结果
        if data['status'] == '200':
            pass

    def min(self):
        self.showMinimized()

    def closed(self):
        sys.exit()

    def msgFrameShow(self, type, msg):
        self.msgLabel.setText(msg)
        if type == '200':
            self.msgLabel.setStyleSheet("color: #00FF00;")
            self.MainWindow = mainWindow()
            self.close()
            self.MainWindow.show()
        elif type == '299':
            self.msgLabel.setStyleSheet("color: #00FF00;")
        else:
            self.msgLabel.setStyleSheet("color:#FF0000;")

#主窗口
class mainWindow(QMainWindow, Ui_MainWindow):
    log_signal = pyqtSignal(str)
    def __init__(self):
        super().__init__()
        self.currVersion =  AppConfig.AppInfo.VERSION + ' 作者:' + AppConfig.AppInfo.AUTHOR + ' 公众号:' + AppConfig.AppInfo.ORGANIZATION
        self.dataType = None #选中的数据类型:昨日,7日,30日
        self.next_txt = None#定时任务下次运行时间
        self.tb_timer_start_time = None#定时任务开始时间
        self.tb_interval = None#定时任务运行间隔
        self.min_wait_time = None #最小等待时间
        self.max_wait_time = None #最大等待时间
        self.chrome_process = None #打开的浏览器实例
        self.timer = None
        self.setupUi(self)
        self.base_dir = os.getcwd()
        apply_stylesheet(self, theme='light_blue.xml', invert_secondary=True)
        self.logger = Logger(self.tb_log).get_logger()
        self.db = DBManager()  # 全局数据库对象
        self.initUI()
        # ====================================================== 设置窗口标题,版本信息=========================================================================
        versionTitle = 'AutoGET V' + self.currVersion
        self.setWindowTitle(versionTitle)
        # 操作文档
        open_web_action = QAction('操作文档', self)
        open_web_action.triggered.connect(self.open_web)
        self.toolBar.addAction(open_web_action)

        # 下载视觉识别支持库
        CRX_action = QAction('下载依赖库', self)
        CRX_action.setToolTip('下载后的文件放置路径为AutoGet所在文件夹的download/ocr下')  # 鼠标悬浮提示
        CRX_action.triggered.connect(self.start_download)
        self.toolBar.addAction(CRX_action)

    def initUI(self):
        self.init_store_table()
        self.init_product_table()
        self.load_log_file()
        self.qStartDate.setDate(QDate.currentDate())
        self.qEndDate.setDate(QDate.currentDate())
        self.qDataType.addItems(AppConfig.AppInfo.DATATYPE)
        self.qDataType.setCurrentText("昨日")
        self.qDataType.setItemDelegate(ComboBoxDelegate())
        self.productTable.setAlternatingRowColors(True)
        self.storeTable.setAlternatingRowColors(True)
        self.apply_button_styles()

        # 创建视觉识别保存目录
        img_path = os.path.join(self.base_dir, AppConfig.Path.OCR_DIR)
        os.makedirs(img_path, exist_ok=True)
    def open_web(self):
        '''
        打开在线版帮助文档
        :return:
        '''
        url = QUrl("https://kdocs.cn/l/cqDRAr0mjBNK")
        QDesktopServices.openUrl(url)

    def start_download(self):
        '''
        下载依赖库
        :return:
        '''
        self.logger.info("开始检查依赖库...")
        self.downThread = DownloadThread(self.logger)
        self.downThread.status_signal.connect(self.update_status)
        self.downThread.start()

    def update_status(self, message):
        self.statusBar.showMessage(message)

    def init_store_table(self):
        self.storeTable.setColumnCount(3)
        self.storeTable.setHorizontalHeaderLabels(['店铺名称', '用户名', '获取标识'])
        self.storeTable.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.storeTable.setSelectionMode(QAbstractItemView.SingleSelection)
        stores = self.db.get_all_stores_dict()
        self.storeTable.setRowCount(len(stores))

        for row, store in enumerate(stores):
            for col, value in enumerate([
                store['store_name'],
                store['username'],
                '是' if store['flag'] else '否'
            ]):
                item = QTableWidgetItem(str(value))
                item.setFlags(item.flags() & ~Qt.ItemIsEditable)  # 设置为不可编辑
                self.storeTable.setItem(row, col, item)

        self.storeTable.resizeColumnsToContents()
        # self.storeTable.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) 所有列平分宽度

    def init_product_table(self):
        self.productTable.setColumnCount(4)
        self.productTable.setHorizontalHeaderLabels(['商品ID', '描述', '所属店铺', '获取标识'])
        self.productTable.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.productTable.setSelectionMode(QAbstractItemView.SingleSelection)
        products = self.db.get_all_products_dict()
        self.productTable.setRowCount(len(products))

        for row, product in enumerate(products):
            for col, value in enumerate([
                product['product_id'],
                product['description'],
                product['store_name'],
                '是' if product['flag'] else '否'
            ]):
                item = QTableWidgetItem(str(value))
                item.setFlags(item.flags() & ~Qt.ItemIsEditable)  # 设置为不可编辑
                self.productTable.setItem(row, col, item)

        self.productTable.resizeColumnsToContents()
        # self.productTable.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

    def load_log_file(self):
        log_path = os.path.join(self.base_dir, AppConfig.Path.LOG_FILE)

        if not os.path.exists(log_path):
            self.tb_log.setPlainText("未读取到日志文件")
            return

        def try_read_lines(encoding):
            try:
                with open(log_path, 'r', encoding=encoding, errors='ignore') as f:
                    lines = f.readlines()[-AppConfig.Log.MAX_LINES:]
                    return ''.join(lines)
            except Exception:
                return None

        content = try_read_lines('utf-8') or try_read_lines('gbk') or "未能解析日志文件"

        self.tb_log.setPlainText(content)

        # 滚动到底部（延迟防止 UI 卡顿）
        QTimer.singleShot(100,lambda: self.tb_log.verticalScrollBar().setValue(self.tb_log.verticalScrollBar().maximum()))

    def refresh_tables(self):
        self.refresh_store_table()
        self.refresh_product_table()
        # 设置交替行颜色
        self.productTable.setAlternatingRowColors(True)
        self.storeTable.setAlternatingRowColors(True)
        self.storeTable.setEditTriggers(QTableWidget.NoEditTriggers)  # 禁止编辑
        self.productTable.setEditTriggers(QTableWidget.NoEditTriggers)  # 禁止编辑
        self.storeTable.resizeColumnsToContents()
        self.productTable.resizeColumnsToContents()

    def refresh_store_table(self):
        stores = self.db.get_all_stores_dict()
        self.storeTable.setColumnCount(3)
        self.storeTable.setRowCount(len(stores))
        for row, store in enumerate(stores):
            self.storeTable.setItem(row, 0, QTableWidgetItem(store['store_name']))
            self.storeTable.setItem(row, 1, QTableWidgetItem(store['username']))
            self.storeTable.setItem(row, 2, QTableWidgetItem("是" if store['flag'] else "否"))

        self.storeTable.resizeColumnsToContents()
        self.storeTable.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

    def refresh_product_table(self):
        products = self.db.get_all_products_dict()
        self.productTable.setRowCount(len(products))
        for row, product in enumerate(products):
            self.productTable.setItem(row, 0, QTableWidgetItem(product['product_id']))
            self.productTable.setItem(row, 1, QTableWidgetItem(product['description']))
            self.productTable.setItem(row, 2, QTableWidgetItem(product['store_name']))
            self.productTable.setItem(row, 3, QTableWidgetItem("是" if product['flag'] else "否"))

        self.productTable.resizeColumnsToContents()
        self.productTable.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

    #交互效果
    def apply_button_styles(self):
        for btn in self.findChildren(QPushButton):
            btn.setStyleSheet("""
                QPushButton:hover {
                    background-color: #e8f0fe;
                    border: 1px solid #1669c1;
                }
                QPushButton:pressed {
                    background-color: #d2e3fc;
                    border: 1px solid #0b57d0;
                }
            """)
        # 表格样式（QTableWidget 行悬停高亮）
        for table in self.findChildren(QTableWidget):
            table.setAlternatingRowColors(True)
            table.setStyleSheet("""
                QTableWidget::item:hover {
                    background-color: #d8ecff;
                }
            """)
            table.setSelectionBehavior(QAbstractItemView.SelectRows)
            table.setSelectionMode(QAbstractItemView.SingleSelection)

    # 新增店铺
    def openAddStore(self):
        self.storeDialog = AddStoreDialog(self.db,self)
        self.storeDialog.exec_()
        self.refresh_tables()

    # 修改店铺
    def changeStore(self):
        self.storeDialog = EditStoreDialog(self.db, self)
        self.storeDialog.exec_()
        self.refresh_tables()

    # 新增商品
    def openAddProduct(self):
        self.productDialog = AddProductDialog(self.db,self)
        self.productDialog.exec_()
        self.refresh_tables()

    # 修改商品
    def changeProduct(self):
        self.productDialog = EditProductDialog(self.db, self)
        self.productDialog.exec_()
        self.refresh_tables()

    def closeEvent(self, event):
        if self.chrome_process:
            try:
                self.chrome_process.terminate()
                self.chrome_process.wait(timeout=5)
            except Exception:
                self.chrome_process.kill()  # 强制结束
        self.db.close()  # 程序关闭时释放连接
        super().closeEvent(event)

    def openChrome(self):
        chrome_path = utils.get_chrome_path(self)
        if not chrome_path:
            self.logger.info("未找到谷歌浏览器安装位置")
            return False

        msg = '已打开指定端口浏览器,请登录'
        try:
            user_data_dir = os.path.join(self.base_dir, AppConfig.Chrome.USER_DATA_DIR)
            os.makedirs(user_data_dir, exist_ok=True)
            # 检查是否已有实例运行
            try:
                response = requests.get(AppConfig.Chrome.CDP_URL)
                if response.status_code == 200:
                    self.logger.info('已有目标浏览器实例运行，已连接,请登录')
                    return True
            except requests.exceptions.RequestException:
                pass  # 没有实例，继续启动

            # 启动浏览器
            command = f'"{chrome_path}" --remote-debugging-port=9333 --user-data-dir="{user_data_dir}" --disable-blink-features=AutomationControlled --disable-infobars'
            self.chrome_process = subprocess.Popen(command, shell=True)

            # 等待端口开放
            for _ in range(20):
                try:
                    response = requests.get(AppConfig.Chrome.CDP_URL)
                    if response.status_code == 200:
                        msg = '指定端口谷歌浏览器已启动，请登录或点击开始定时任务'
                        break
                except Exception as e:
                    msg = "指定端口浏览器打开失败"
                    pass
                time.sleep(0.5)
            return True
        except Exception as e:
            return False
        finally:
            self.logger.info(msg)

    def startTask(self):
        if not self.storeBox.isChecked() and self.productBox.isChecked():
            QMessageBox.critical(self, "错误", '不能仅获取商品数据!')
            return
        if not self.storeBox.isChecked() and not self.productBox.isChecked():
            QMessageBox.critical(self, "错误", '至少选择一种要下载的数据!')
            return
        # 创建弹窗
        dialog = TimerDialog(self)
        if dialog.exec_():  # 如果点击了确定
            start_time = dialog.get_start_time()  # 获取定时任务开始时间
            interval = dialog.get_interval()  # 获取定时任务运行间隔（分钟）
            self.min_wait_time, self.max_wait_time = dialog.get_wait_time()  # 获取最小等待时间# 获取最大等待时间
            if self.min_wait_time > self.max_wait_time:
                QMessageBox.critical(self, "错误", '最小随机等待时间不能大于最大随机等待时间!')
                return
            checked_button = self.buttonGroup.checkedButton()
            if checked_button:
                self.dataType = checked_button.text()

            # 转换为毫秒
            interval_ms = interval * 60 * 1000

            # 设置定时任务开始时间
            self.tb_timer_start_time = start_time
            self.tb_interval = interval

            # 启动定时任务
            self.start_timer(interval_ms)

    def start_timer(self, interval_ms):
        # 获取当前时间与定时任务开始时间的时间差
        current_time = QDateTime.currentDateTime()
        time_diff = self.tb_timer_start_time.toMSecsSinceEpoch() - current_time.toMSecsSinceEpoch()

        # 如果定时任务的启动时间在未来，使用 QTimer.singleShot 延迟到指定时间
        if time_diff > 0:
            QTimer.singleShot(time_diff, self.start_worker)
            self.logger.info(f'定时任务已设置,启动时间:{self.tb_timer_start_time.toString("yyyy-MM-dd HH:mm:ss")},运行间隔:{self.tb_interval}分钟')
        else:
            # 如果指定时间已经过去，则立即执行
            self.start_worker()
            self.logger.info(f'定时任务已设置,启动时间{self.tb_timer_start_time.toString("yyyy-MM-dd HH:mm:ss")}在过去,立即执行任务,运行间隔:{self.tb_interval}分钟')

        # 启动定时器，在指定的间隔时间后定期执行任务
        if not self.timer:
            self.timer = QTimer()
            self.timer.timeout.connect(self.start_worker)

        # 启动定时器
        self.timer.start(interval_ms)

    def start_worker(self):
        self.logger.info('自动获取任务已开始...')
        try:
            openStatus = self.openChrome()
            if openStatus:
                self.work = WorkerThread(self.logger,self.min_wait_time,self.max_wait_time,self.dataType,self.storeBox.isChecked(),self.productBox.isChecked())
                self.work.finished.connect(self.on_finished)  # 连接信号
                self.work.status_signal.connect(self.update_status)
                self.work.start()

                # 计算下次执行时间
                zint = self.tb_interval * 60 * 1000
                self.tb_timer_start_time = self.tb_timer_start_time.addMSecs(zint)# 更新计算下次执行时间
                self.next_txt = '下次运行时间:' + self.tb_timer_start_time.toString("yyyy-MM-dd HH:mm:ss")
                self.tb_next_date.setText(self.next_txt)  # 更新标签显示时间
        except Exception as e:
            self.logger.error(f'任务执行失败;{str(e)}')

    def stopTask(self):
        if self.timer is not None:
            self.timer.stop()  # 停止定时器
            self.timer = None  # 重置定时器
            self.tb_next_date.setText('下次运行时间:未设置')
            self.logger.info('定时任务已停止')

    def queryData(self):
        start_date = self.qStartDate.date().toString("yyyy-MM-dd")
        end_date = self.qEndDate.date().toString("yyyy-MM-dd")
        data_type = self.qDataType.currentText()
        store_name = self.qStoreName.text()
        product_id = self.qProductId.text()
        product_name = self.qProductName.text()

        # 查询店铺数据
        headers1, rows1 = self.db.query_table_data(
            table_name=AppConfig.DB.STORE_DATA_TABLE,
            start_date=start_date,
            end_date=end_date,
            data_type=data_type,
            store_name=store_name
        )
        self.fill_table(self.storeTableView, headers1, rows1)

        # 查询商品数据
        headers2, rows2 = self.db.query_table_data(
            table_name=AppConfig.DB.PRODUCT_DATA_TABLE,
            start_date=start_date,
            end_date=end_date,
            data_type=data_type,
            store_name=store_name,
            product_id=product_id,
            product_name=product_name
        )
        self.fill_table(self.productTableView, headers2, rows2)
        # 设置交替行颜色
        self.storeTableView.setAlternatingRowColors(True)
        self.productTableView.setAlternatingRowColors(True)
        # 设置禁止编辑
        self.storeTableView.setEditTriggers(QTableWidget.NoEditTriggers)  # 禁止编辑
        self.productTableView.setEditTriggers(QTableWidget.NoEditTriggers)  # 禁止编辑

    def fill_table(self, table_widget, headers, data):
        table_widget.clear()  # 清空表格
        table_widget.setColumnCount(len(headers))  # 设置列数
        table_widget.setRowCount(len(data))  # 设置行数
        zh_headers = [AppConfig.DB.COLUMN_NAME_MAP.get(col, col) for col in headers]  # 获取中文列头
        table_widget.setHorizontalHeaderLabels(zh_headers)  # 设置表头

        for row_idx, row in enumerate(data):
            for col_idx, value in enumerate(row):
                item = QTableWidgetItem(str(value))  # 创建每个单元格
                table_widget.setItem(row_idx, col_idx, item)  # 设置单元格内容

        table_widget.resizeColumnsToContents()  # 自动调整列宽
        # 设置行选中：多选和单选的设置
        table_widget.setSelectionBehavior(table_widget.SelectRows)  # 行选择模式
        table_widget.setSelectionMode(table_widget.SingleSelection)  # 单行选中

    def exportDataToExcel(self):
        path, _ = QFileDialog.getSaveFileName(self, "保存 Excel 文件", "", "Excel 文件 (*.xlsx)")
        if not path:
            return

        wb = Workbook()
        ws1 = wb.active
        ws1.title = '店铺数据'
        ws2 = wb.create_sheet('商品数据')

        # 写入第一个表格（店铺数据）
        self._write_table_to_sheet(self.storeTableView, ws1)

        # 写入第二个表格（商品数据）
        self._write_table_to_sheet(self.productTableView, ws2)

        wb.save(path)
        self.logger.info(f"数据成功导出到 {path}")
        self.update_status(f"数据成功导出到 {path}")

    def _write_table_to_sheet(self, table: QTableWidget, sheet):
        # 写表头
        for col in range(table.columnCount()):
            header = table.horizontalHeaderItem(col).text()
            sheet.cell(row=1, column=col + 1, value=header)

        # 写数据
        for row in range(table.rowCount()):
            for col in range(table.columnCount()):
                item = table.item(row, col)
                sheet.cell(row=row + 2, column=col + 1, value=item.text() if item else '')

    def on_finished(self):
        self.logger.info(f'-本次自动获取任务已结束')


def setup_translator(app):
    translator = QTranslator()
    qt_translator_path = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
    if translator.load("qt_zh_CN.qm", qt_translator_path):
        app.installTranslator(translator)

def main():
    app = QApplication(sys.argv)
    setup_translator(app)  # 设置中文语言
    app.setAttribute(Qt.AA_EnableHighDpiScaling)
    import warnings
    warnings.filterwarnings('ignore')

    window = Window()
    # window = mainWindow()
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
